package com.wenbing.miio.core;

import com.wenbing.miio.core.exception.NetworkLayerException;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * 协议栈 层
 * @author wen bing
 * @projectName: miio
 * @package: com.wenbing.miio.core
 * @className: DisLayer
 * @date 2024/09/23 21:38
 **/
public abstract class NetworkStackLayer extends AbstractShareContextNetworkLayer implements NetworkStack {

    private OutboundConsumerNetworkLayer writeCacheAdaptLayer;

    private InboundConsumerNetworkLayer readCacheAdaptLayer;

    protected NetworkStackLayer() {
        this.readCacheAdaptLayer = new InboundConsumerNetworkLayer((frame) -> {
            this.deliverNextLayer(frame.getContext(), frame.getByteBuffer());
        });

        this.writeCacheAdaptLayer = new OutboundConsumerNetworkLayer((frame) -> {
            this.deliverPreviousLayer(frame.getContext(), frame.getByteBuffer());
        });

        NetworkLayerNode readCacheNode = this.readCacheAdaptLayer.getNetworkLayerNode();
        NetworkLayerNode writeCacheNode = this.writeCacheAdaptLayer.getNetworkLayerNode();
        NetworkLayerNode.link(writeCacheNode, readCacheNode);
        readCacheNode.setNetworkStack(this);
        writeCacheNode.setNetworkStack(this);
    }

    /**
     * 是否匹配该协议栈
     * @param context
     * @param packingData
     * @return
     */
    protected abstract boolean inboundCondition(NetworkLayerContext context, ByteBuffer packingData);

    protected abstract boolean outboundCondition(NetworkLayerContext context, ByteBuffer packingData);

    @Override
    public void boot() {
        NetworkLayer layer = writeCacheAdaptLayer;
        while (layer != null) {
            if (layer instanceof Bootable bootable) {
                bootable.boot();
            }
            layer = layer.getNetworkLayerNode().getLowerLayer();
            if (layer == writeCacheAdaptLayer)
                throw new RuntimeException("circular layers is not supported");
        }
    }

    @Override
    public void addLowerLayer(NetworkLayer layer) {
        NetworkLayerNode node = this.readCacheAdaptLayer.getNetworkLayerNode()
                .getUpperLayerNode();
        NetworkLayerNode newNode = layer.getNetworkLayerNode();
        newNode.setNetworkStack(this);
        NetworkLayerNode.link(node, newNode);
        NetworkLayerNode.link(newNode, this.readCacheAdaptLayer.getNetworkLayerNode());
        LOGGER.info("{} add layer {} success", this, layer);
    }

    /**
     * 分发到 父协议栈 的下层
     * @param context
     * @param packingData
     * @throws NetworkLayerException
     * @throws IOException
     */
    protected void deliverNextLayer(NetworkLayerContext context, ByteBuffer packingData) throws NetworkLayerException, IOException {
        super.deliverLowerLayer(context, packingData);
    }

    /**
     * 分发到 父协议栈 的上层
     * @param context
     * @param packingData
     * @throws NetworkLayerException
     * @throws IOException
     */
    protected void deliverPreviousLayer(NetworkLayerContext context, ByteBuffer packingData) throws NetworkLayerException, IOException {
        super.deliverUpperLayer(context, packingData);
    }

    /**
     * 分发到子协议栈进行解码操作
     * @param context
     * @param packingData
     * @throws NetworkLayerException
     * @throws IOException
     */
    @Override
    protected void deliverLowerLayer(NetworkLayerContext context, ByteBuffer packingData) throws NetworkLayerException, IOException {
        writeCacheAdaptLayer.inbound(context, packingData);
    }

    /**
     * 分发到子协议栈进行编码操作
     * @param context
     * @param packingData
     * @throws NetworkLayerException
     * @throws IOException
     */
    @Override
    protected void deliverUpperLayer(NetworkLayerContext context, ByteBuffer packingData) throws NetworkLayerException, IOException {
        readCacheAdaptLayer.outbound(context, packingData);
    }

    protected NetworkLayer getFirstNetworkLayer() {
        return writeCacheAdaptLayer;
    }
}
